/*
 *   Copyright 2008 Francois Fernandes
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package com.googlecode.opendoclibrary.internal.impl.fs;

import java.io.File;
import java.util.Dictionary;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;

import com.googlecode.opendoclibrary.library.spi.ILibrary;

/**
 * @author Francois Fernandes
 * 
 */
public class FilesystemLibraryFactory implements ManagedServiceFactory
{
    private Logger log = Logger.getLogger( FilesystemLibrary.class );

    private final Map<String, ServiceRegistration> registeredLibraries;

    private final BundleContext bundleContext;

    /**
     * 
     */
    public FilesystemLibraryFactory( BundleContext bundleContext )
    {
        this.bundleContext = bundleContext;
        registeredLibraries = new ConcurrentHashMap<String, ServiceRegistration>();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.osgi.service.cm.ManagedServiceFactory#deleted(java.lang.String)
     */
    @Override
    public void deleted( String pid )
    {
        ServiceRegistration reg = registeredLibraries.get( pid );
        if ( reg == null )
        {
            log.error( "no such registered service: " + pid );
            return;
        }
        log.info( "unregistering filesystem library: " + pid + " (name: "
                        + reg.getReference().getProperty( ILibrary.NAME ) + ")" );
        reg.unregister();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.osgi.service.cm.ManagedServiceFactory#getName()
     */
    @Override
    public String getName()
    {
        return "Filesystem library factory";
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.osgi.service.cm.ManagedServiceFactory#updated(java.lang.String, java.util.Dictionary)
     */
    @Override
    public void updated( String pid, Dictionary properties ) throws ConfigurationException
    {
        try
        {
            ServiceRegistration reg = registeredLibraries.get( pid );
            if ( reg == null )
            {
                log.info( "creating filesystem library with pid " + pid );
                String libraryName = getString( properties, ILibrary.NAME, true );
                String libraryLocation = getString( properties, IFilesystemLibrary.LIBRARY_LOCATION, true );
                
                File libraryHome = new File( libraryLocation );
                if ( libraryHome.exists() )
                {
                    if ( !libraryHome.isDirectory() )
                    {
                        throw new ConfigurationException( IFilesystemLibrary.LIBRARY_LOCATION, "" );
                    }
                    validateLibraryHome( libraryHome );
                }
                else
                {
                    if ( !libraryHome.mkdirs() )
                    {
                        throw new ConfigurationException( IFilesystemLibrary.LIBRARY_LOCATION,
                                                          "unable to create library home. Failed to create directory." );
                    }
                }
                
                Properties props = new Properties();
                props.setProperty( ILibrary.NAME, libraryName );
                reg = bundleContext.registerService( ILibrary.class.getName(), new FilesystemLibrary( libraryHome ), props );
                registeredLibraries.put( pid, reg );
            }
            else
            {
                // FIXME make this more detailed and maybe allow library.name to be changed
                throw new ConfigurationException( "", "configuration changes are not allowed" );
            }
        }
        catch ( ConfigurationException e )
        {
            log.error( e.getMessage() );
            throw e;
        }
    }

    /**
     * @param libraryHome
     */
    protected void validateLibraryHome( File libraryHome ) throws ConfigurationException
    {
        // FIXME implement checking logic
    }

    private String getString( Dictionary properties, String prop, boolean required ) throws ConfigurationException
    {
        Object value = properties.get( prop );
        if ( value == null )
        {
            if ( required )
            {
                throw new ConfigurationException( prop, "required property missing" );
            }
            return null;

        }
        if ( value instanceof String )
        {
            if ( required && ( (String) value ).trim().length() == 0 )
            {
                throw new ConfigurationException( prop, "required property missing" );
            }
            return (String) value;
        }
        throw new ConfigurationException( prop, ( "property of wrong type. Expected type: " + String.class.getName()
                        + ", actual: " + value.getClass().getName() ) );
    }

    
}
